from flask import Blueprint, request, jsonify
from datetime import datetime, date
import logging
import time
import pymysql
import json
import requests
import re
from ..utils import validate_user_id, device_required, db_connection
from ..config import Config
import bcrypt
from openai import OpenAI
from ..models import User, Device, db, Song, Artist
from ..database import mongo_collection
from sqlalchemy import or_
from ..utils.ip_utils import get_client_ip

user_bp = Blueprint('user', __name__)
logger = logging.getLogger('UserActions')

@user_bp.route('/v1/bind', methods=['POST'])
def bind_device():
    """
    用户绑定设备接口
    请求示例：
    {
        "device_id": "CQUCHX0503001",
        "user_id": "user123",
        "timestamp": 1678901234
    }
    """
    try:
        # ==================== 请求验证阶段 ====================
        # 验证JSON格式
        if not request.is_json:
            logger.warning("非JSON请求")
            return jsonify(
                code=Config.ERROR_CODES['INVALID_JSON'][0], 
                message=Config.ERROR_CODES['INVALID_JSON'][1]
            ), 400
            
        data = request.get_json()
        
        # 校验必要字段
        required_fields = ['device_id', 'user_id', 'secret', 'timestamp']
        if missing := [f for f in required_fields if f not in data]:
            logger.warning(f"缺少必要字段: {', '.join(missing)}")
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message=f"{Config.ERROR_CODES['MISSING_FIELD'][1]}: {', '.join(missing)}"
            ), 400
            
        req_device_id = data['device_id']
        user_id = data['user_id']
        secret = data['secret']
        timestamp = data['timestamp']

    # ==================== 安全验证阶段 ====================
        # 时间戳验证（±5分钟）
        try:
            # 将毫秒级时间戳转换为秒
            client_timestamp = int(timestamp) / 1000  
            current_timestamp = time.time()
            time_diff = abs(current_timestamp - client_timestamp)
            
            if time_diff > 300:
                logger.warning(f"过期时间戳: {timestamp} (转换后:{client_timestamp}), 当前时间戳: {current_timestamp}, 差: {time_diff}")
                return jsonify(
                    code=Config.ERROR_CODES['EXPIRED_TIMESTAMP'][0],
                    message=Config.ERROR_CODES['EXPIRED_TIMESTAMP'][1]
                ), 401
        except ValueError:
            logger.warning(f"非法时间戳格式: {timestamp}")
            return jsonify(
                code=40008,
                message="时间戳必须为13位毫秒级整数"
            ), 400
        
        # ==================== 数据库操作阶段 ====================
        try:
            # 使用ORM查询设备
            device = Device.query.get(req_device_id)
            
            if not device:
                logger.error(f"设备不存在: {req_device_id}")
                return jsonify(
                    code=404, 
                    message="设备未注册"
                ), 404
            
            # 验证secret有效性
            if device.device_key != secret:
                logger.warning(f"密钥验证失败 设备:{req_device_id}")
                return jsonify(
                    code=Config.ERROR_CODES['INVALID_SECRET'][0],
                    message=Config.ERROR_CODES['INVALID_SECRET'][1]
                ), 403

            current_user = device.user_id
            
            # 冲突检测（设备已被绑定）
            if current_user and current_user != int(user_id):
                logger.warning(
                    f"设备已被占用 当前用户:{current_user} 请求用户:{user_id}"
                )
                return jsonify(
                    code=40112, 
                    message="设备已被其他用户绑定"
                ), 401

            # 执行绑定/更新操作
            device.user_id = int(user_id)
            db.session.commit()
            
            # 记录绑定日志到MongoDB
            with mongo_collection(Config.MONGODB_COLLECTIONS["device_bind_logs"]) as collection:
                collection.insert_one({
                    "device_id": req_device_id,
                    "user_id": int(user_id),
                    "operation": "bind",
                    "timestamp": datetime.now()
                })
                
        except Exception as e:
            db.session.rollback()
            logger.error(f"数据库操作失败: {str(e)}")
            return jsonify(
                code=50002,
                message="数据库服务异常"
            ), 500

        logger.info(f"绑定成功 设备:{req_device_id} 用户:{user_id}")
        return jsonify(
            code=0,
            user_id=user_id,
            device_id=req_device_id,
            bind_at=datetime.utcnow().isoformat() + "Z"
        ), 200

    except Exception as e:
        logger.exception("绑定流程异常")  # 记录完整堆栈
        return jsonify(
            code=50000, 
            message="系统繁忙，请稍后重试"
        ), 500

@user_bp.route('/v1/unbind', methods=['POST'])
@device_required
def unbind_device(device_id):
    """
    用户解绑设备接口
    请求示例：
    {
        "device_id": "CQUCHX0503001",
        "user_id": "user123", 
        "timestamp": 1678901234
    }
    """
    try:
        # 请求格式验证
        if not request.is_json:
            return jsonify(
                code=Config.ERROR_CODES['INVALID_JSON'][0], 
                message=Config.ERROR_CODES['INVALID_JSON'][1]
            ), 400

        data = request.get_json()
        required_fields = ['device_id', 'user_id', 'timestamp']
        if any(field not in data for field in required_fields):
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message=Config.ERROR_CODES['MISSING_FIELD'][1]
            ), 400

        req_device_id = data['device_id']
        user_id = data['user_id']
        timestamp = data['timestamp'] / 1000

        # 设备ID双重验证
        if req_device_id != device_id:
            logger.warning(f"设备ID不匹配 请求:{req_device_id} 实际:{device_id}")
            return jsonify(
                code=403,
                message="Device ID mismatch"
            ), 403

        # 用户ID有效性验证
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="Invalid user ID format"
            ), 400

        # 时间戳有效性验证
        if abs(time.time() - int(timestamp)) > 300:
            return jsonify(
                code=Config.ERROR_CODES['EXPIRED_TIMESTAMP'][0],
                message=Config.ERROR_CODES['EXPIRED_TIMESTAMP'][1]
            ), 401

        # 数据库事务处理
        try:
            # 使用ORM查询设备
            device = Device.query.get(device_id)
            
            if not device:
                return jsonify(
                    code=404, 
                    message="Device not found"
                ), 404
            
            current_user = device.user_id
            
            # 状态检查
            if current_user is None:
                return jsonify(
                    code=40109,
                    message="Device not bound"
                ), 401
                
            if current_user != int(user_id):
                return jsonify(
                    code=40301,
                    message="Unauthorized operation"
                ), 403

            # 执行解绑操作
            device.user_id = None
            db.session.commit()
                
            # 记录解绑日志到MongoDB
            with mongo_collection(Config.MONGODB_COLLECTIONS["device_bind_logs"]) as collection:
                collection.insert_one({
                    "device_id": device_id,
                    "user_id": int(user_id),
                    "operation": "unbind",
                    "timestamp": datetime.now()
                })
                
        except Exception as e:
            db.session.rollback()
            logger.error(f"解绑异常: {str(e)}")
            return jsonify(
                code=50000, 
                message="Internal server error"
            ), 500

        logger.info(f"设备解绑成功 设备:{device_id} 用户:{user_id}")
        return jsonify(
            code=0,
            user_id=user_id,
            device_id=device_id,
            unbound_at=datetime.utcnow().isoformat() + "Z"
        ), 200

    except Exception as e:
        logger.error(f"解绑异常: {str(e)}")
        return jsonify(
            code=50000, 
            message="Internal server error"
        ), 500
        
@user_bp.route('/v1/register', methods=['POST'])
def register():
    try:
        # 1. 获取并校验请求数据
        if not request.is_json:
            return jsonify({
                "code": Config.ERROR_CODES['INVALID_JSON'][0],
                "message": Config.ERROR_CODES['INVALID_JSON'][1]
            }), 400

        data = request.get_json()
        username = data.get('username')
        password = data.get('password')
        phonenumber = data.get('phonenumber')  # 获取手机号字段
        
        # 验证必填字段
        if not username or not password:
            return jsonify({
                "code": Config.ERROR_CODES['MISSING_FIELD'][0],
                "message": f"{Config.ERROR_CODES['MISSING_FIELD'][1]}: username/password"
            }), 400
            
        # 修复手机号验证逻辑
        if phonenumber is not None:
            # 确保手机号是字符串类型
            phonenumber = str(phonenumber)
            if not (phonenumber.isdigit() and len(phonenumber) == 11):
                return jsonify({
                    "code": 40013,
                    "message": "手机号格式不正确"
                }), 400

        # 2. 哈希密码
        password_bytes = password.encode('utf-8')
        salt = bcrypt.gensalt()
        hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')

        # 3. 使用ORM创建用户
        try:
            # 检查用户名是否已存在
            existing_user = User.query.filter_by(user_name=username).first()
            if existing_user:
                logger.warning(f"用户名重复: {username}")
                return jsonify(
                    code=Config.ERROR_CODES['DUPLICATE_USER'][0],
                    message=Config.ERROR_CODES['DUPLICATE_USER'][1]
                ), 400
            
            # 创建新用户，添加手机号字段
            new_user = User(
                user_name=username,
                user_key=hashed_password,
                phonenumber=phonenumber,  # 添加手机号
                register_at=datetime.now()
            )
            
            db.session.add(new_user)
            db.session.commit()
            
            # 记录注册日志到MongoDB
            with mongo_collection(Config.MONGODB_COLLECTIONS["user_logs"]) as collection:
                collection.insert_one({
                    "user_id": new_user.user_id,
                    "username": username,
                    "phonenumber": phonenumber,  # 添加手机号到日志
                    "operation": "register",
                    "timestamp": datetime.now()
                })
            
            return jsonify({
                "code": 0,
                "user_id": new_user.user_id,
                "message": "注册成功"
            }), 200
            
        except Exception as e:
            db.session.rollback()
            logger.error(f"用户创建失败: {str(e)}")
            raise

    except pymysql.IntegrityError:
        logger.warning(f"用户名重复: {username}")
        return jsonify(
            code=Config.ERROR_CODES['DUPLICATE_USER'][0],
            message=Config.ERROR_CODES['DUPLICATE_USER'][1]
        ), 400
    except Exception as e:
        logger.exception(f"注册异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500
            
@user_bp.route('/v1/login', methods=['POST'])
def login():
    try:
        # 1. 获取并校验请求数据
        if not request.is_json:
            return jsonify(
                code=Config.ERROR_CODES['INVALID_JSON'][0],
                message=Config.ERROR_CODES['INVALID_JSON'][1]
            ), 400

        data = request.get_json()
        username = data.get('username')
        password = data.get('password')
        
        if not username or not password:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message=f"{Config.ERROR_CODES['MISSING_FIELD'][1]}: username/password"
            ), 400

        # 2. 使用ORM查询用户
        user = User.query.filter_by(user_name=username).first()
        
        if not user:
            logger.warning(f"用户不存在: {username}")
            return jsonify(
                code=Config.ERROR_CODES['AUTH_FAILED'][0],
                message=Config.ERROR_CODES['AUTH_FAILED'][1]
            ), 401

        # 3. 密码验证
        user_input_password = password.encode('utf-8')
        stored_password = user.user_key.encode('utf-8')  # 使用 user_key 而不是 password
        
        if not bcrypt.checkpw(user_input_password, stored_password):
            logger.warning(f"密码错误: {username}")
            return jsonify(
                code=Config.ERROR_CODES['AUTH_FAILED'][0],
                message=Config.ERROR_CODES['AUTH_FAILED'][1]
            ), 401

        # 4. 获取用户绑定的设备
        devices = Device.query.filter_by(user_id=user.user_id).all()
        device_list = [{
            "device_id": device.device_id,
            "secret": device.device_key
        } for device in devices]
        
        # 5. 记录登录日志到MongoDB
        with mongo_collection(Config.MONGODB_COLLECTIONS["user_logs"]) as collection:
            collection.insert_one({
                "user_id": user.user_id,
                "username": username,
                "operation": "login",
                "timestamp": datetime.now(),
                "ip": get_client_ip()
            })

        return jsonify({
            "code": 0,
            "user_id": user.user_id,
            "username": user.user_name,
            "devices": device_list
        }), 200

    except Exception as e:
        logger.exception(f"登录异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500


@user_bp.route('/v1/records', methods=['GET'])
def get_listen_history():
    """
    获取用户设备历史听歌数据接口
    请求示例：/api/v1/records?user_id=123&start_date=2023-01-01&end_date=2023-12-31&page=1&page_size=10
    """
    try:
        # 获取查询参数
        user_id = request.args.get('user_id')
        start_date = request.args.get('start_date')
        end_date = request.args.get('end_date')
        
        # 获取分页参数
        try:
            page = int(request.args.get('page', 1))
            page_size = int(request.args.get('page_size', 10))
            if page < 1 or page_size < 1:
                return jsonify(
                    code=40010,
                    message="页码和每页数量必须为正整数"
                ), 400
        except ValueError:
            return jsonify(
                code=40010,
                message="页码和每页数量必须为整数"
            ), 400
        
        # 参数验证
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
            
        # 验证日期格式
        date_format = "%Y-%m-%d"
        try:
            if start_date:
                datetime.strptime(start_date, date_format)
            if end_date:
                datetime.strptime(end_date, date_format)
        except ValueError:
            return jsonify(
                code=40009,
                message="日期格式无效，请使用YYYY-MM-DD格式"
            ), 400
        
        # 构建MongoDB查询条件
        query = {
            "user_id": int(user_id)
        }
        
        # 添加日期过滤条件
        if start_date and end_date:
            query["date"] = {"$gte": start_date, "$lte": end_date}
        elif start_date:
            query["date"] = {"$gte": start_date}
        elif end_date:
            query["date"] = {"$lte": end_date}
        
        # 从listen_records集合查询数据 - 只查询，不记录日志
        with mongo_collection(Config.MONGODB_COLLECTIONS["listen_records"]) as collection:
            # 获取总记录数
            total_records = collection.count_documents(query)
            
            # 计算分页
            total_pages = (total_records + page_size - 1) // page_size
            skip = (page - 1) * page_size
            
            # 查询数据并按时间戳降序排列
            records = list(collection.find(query).sort("timestamp", -1).skip(skip).limit(page_size))
        
        # 构建响应数据
        response_data = {
            "code": 0,
            "user_id": int(user_id),
            "pagination": {
                "page": page,
                "page_size": page_size,
                "total_records": total_records,
                "total_pages": total_pages
            },
            "records": []
        }
        
        # 处理每条记录
        for record in records:
            listen_info = {
                "date": record["date"],
                "timestamp": record["timestamp"].isoformat() if isinstance(record["timestamp"], datetime) else record["timestamp"],
                "song_id": record["song_id"],
                "song_name": record["song_name"],
                "duration": record["duration"],
                "period": record["period"],
                "device_id": record.get("device_id", "")
            }
            
            # 添加艺术家信息（支持新的格式）
            if "artists" in record and isinstance(record["artists"], list):
                listen_info["artists"] = record["artists"]
            else:
                listen_info["artists"] = []
            
            response_data["records"].append(listen_info)
        
        return jsonify(response_data), 200
            
    except Exception as e:
        logger.exception(f"获取听歌历史数据异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500

@user_bp.route('/v1/change_state', methods=['POST'])
def update_device_state():
    """
    更新设备配置接口
    请求示例：
    {
        "user_id": 4,
        "device_id": "CQUCHX0503001",
        "Power_state": "OFF",
        "Audio": {
            "effect": "Rock",
            "mode": "Sequential"
        }
    }
    """
    try:
        if not request.is_json:
            return jsonify(Config.ERROR_CODES['INVALID_JSON']), 400

        data = request.get_json()
        required_fields = ['user_id', 'device_id', 'Audio', 'Power_state']
        if missing := [f for f in required_fields if f not in data]:
            return jsonify(
                code=40002,
                message=f"Missing fields: {', '.join(missing)}"
            ), 400

        # 验证音频配置枚举值
        valid_effects = ['Common', 'Rock', 'Jazz', 'Classical']
        valid_modes = ['Sequential', 'Random', 'Shuffle']
        Power_state = data['Power_state']
        audio_config = data['Audio']
        
        if audio_config['effect'] not in valid_effects:
            return jsonify(code=40014, message="无效的音效模式"), 400
        if audio_config['mode'] not in valid_modes:
            return jsonify(code=40015, message="无效的播放模式"), 400

        # 检查设备存在性
        device_id = data['device_id']
        device = Device.query.get(device_id)
        if not device:
            return jsonify(code=40401, message="设备不存在"), 404

        # 获取当前最新状态
        with mongo_collection(Config.MONGODB_COLLECTIONS["device_status"]) as collection:
            current_status = collection.find_one(
                {"device_id": device_id},
                sort=[("timestamp", -1)]
            )

        # 确定设备状态
        connection_status = "ONLINE"
        if Power_state == "OFF":
            connection_status = "OFFLINE"

        # 确定激活状态
        activation_status = "ACTIVATED" if device.is_activated else "INACTIVATED"
            
        # 准备新状态
        new_status = {
            "device_id": device_id,
            "timestamp": datetime.now(),
            "received_at": datetime.now(),
            "connection_status": connection_status,  # 连接状态：在线/离线
            "activation_status": activation_status,  # 激活状态：激活/未激活
            "power": {
                "state": Power_state,
                "battery_level": current_status.get("power", {}).get("battery_level", 0) if current_status else 0,
                "charging_state": current_status.get("power", {}).get("charging_state", "UNKNOWN") if current_status else "UNKNOWN"
            },
            "network": {
                "wifi_state": current_status.get("network", {}).get("wifi_state", "UNKNOWN") if current_status else "UNKNOWN",
                "net_delay": current_status.get("network", {}).get("net_delay", 0) if current_status else 0
            },
            "audio": {
                "effect": audio_config['effect'],
                "mode": audio_config['mode']
            }
        }

        # 插入新状态到MongoDB
        with mongo_collection(Config.MONGODB_COLLECTIONS["device_status"]) as collection:
            collection.insert_one(new_status)
            
        return jsonify({
            "code": 0,
            "message": "配置更新成功",
            "device_id": device_id,
            "updated_at": datetime.utcnow().isoformat() + "Z"
        }), 200

    except Exception as e:
        logger.exception("配置更新异常")
        return jsonify(code=50000, message="系统繁忙，请稍后重试"), 500

@user_bp.route('/v1/user_profile', methods=['GET'])
def get_user_profile():
    """
    获取用户画像接口
    请求示例：/api/v1/user_profile?user_id=123
    """
    try:
        # 获取查询参数
        user_id = request.args.get('user_id')
        
        # 参数验证
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
            
        # 转换用户ID为整数类型，确保与数据库中的类型一致
        user_id_int = int(user_id)
            
        # 从MySQL获取用户基本信息
        user = User.query.get(user_id_int)
        if not user:
            return jsonify(
                code=404,
                message="用户不存在"
            ), 404
        
        # 获取用户设备
        devices = Device.query.filter_by(user_id=user_id_int).all()
        
        # 构建用户基本信息
        user_data = {
            'basic_info': {
                'user_id': user_id_int,
                'username': user.user_name,
                'register_date': user.register_at.strftime("%Y-%m-%d") if user.register_at else None,
                'phone': user.phonenumber if hasattr(user, 'phonenumber') else None
            },
            'devices': [],
            'listen_stats': {'total_duration': 0, 'days_active': 0},
            'time_preferences': {},
            'hour_preferences': {},  # 新增：按小时统计的时段偏好
            'artist_preferences': {},  # 新增：艺术家偏好
            'listening_patterns': {},  # 新增：听歌模式分析
            'recent_activity': {}
        }
        
        # 获取设备详细信息
        if devices:
            device_ids = []
            for device in devices:
                device_ids.append(device.device_id)
                
                # 获取设备状态
                with mongo_collection(Config.MONGODB_COLLECTIONS["device_status"]) as collection:
                    status = collection.find_one(
                        {"device_id": device.device_id},
                        sort=[("timestamp", -1)]
                    )
                    
                    device_info = {
                        "device_id": device.device_id,
                        "device_key": device.device_key,
                        "create_at": device.create_at.isoformat() if device.create_at else None,
                        "firmware_version": "1.2.0",
                        "is_activated": device.is_activated,
                        "activation_time": device.activation_time.isoformat() if device.activation_time else None,
                        "last_online": status.get("timestamp").isoformat() if status and "timestamp" in status else None,
                        "status": {}
                    }
                    
                    # 添加详细状态信息
                    if status:
                        device_info["status"] = {
                            "connection_status": status.get("connection_status", "UNKNOWN"),
                            "activation_status": status.get("activation_status", "UNKNOWN"),
                            "power": {
                                "state": status.get("power", {}).get("state", "UNKNOWN"),
                                "battery_level": status.get("power", {}).get("battery_level", 0),
                                "charging_state": status.get("power", {}).get("charging_state", "UNKNOWN")
                            },
                            "network": {
                                "wifi_state": status.get("network", {}).get("wifi_state", "UNKNOWN"),
                                "net_delay": status.get("network", {}).get("net_delay", 0)
                            },
                            "audio": {
                                "effect": status.get("audio", {}).get("effect", "Common"),
                                "mode": status.get("audio", {}).get("mode", "Sequential")
                            }
                        }
                    else:
                        # 没有状态记录时的默认值
                        device_info["status"] = {
                            "connection_status": "OFFLINE",
                            "activation_status": "ACTIVATED" if device.is_activated else "INACTIVATED",
                            "power": {
                                "state": "UNKNOWN",
                                "battery_level": 0,
                                "charging_state": "UNKNOWN"
                            },
                            "network": {
                                "wifi_state": "DISCONNECTED",
                                "net_delay": 0
                            },
                            "audio": {
                                "effect": "Common",
                                "mode": "Sequential"
                            }
                        }
                        
                    user_data['devices'].append(device_info)
        else:
            user_data['devices'] = []
        
        # 获取年度统计数据
        with mongo_collection(Config.MONGODB_COLLECTIONS["yearly_preferences"]) as collection:
            yearly_records = list(collection.find({"user_id": user_id_int}))
            
            if not yearly_records:
                # 尝试使用字符串类型的用户ID查询
                yearly_records = list(collection.find({"user_id": user_id}))
        
        # 获取所有听歌记录用于详细分析
        all_listen_records = []
        with mongo_collection(Config.MONGODB_COLLECTIONS["listen_records"]) as collection:
            all_listen_records = list(collection.find({"user_id": user_id_int}).sort("timestamp", 1))
            if not all_listen_records:
                all_listen_records = list(collection.find({"user_id": user_id}).sort("timestamp", 1))
        
        # 分析听歌模式
        if all_listen_records:
            # 分析听歌时间间隔
            time_intervals = []
            for i in range(1, len(all_listen_records)):
                if isinstance(all_listen_records[i].get('timestamp'), datetime) and isinstance(all_listen_records[i-1].get('timestamp'), datetime):
                    interval = (all_listen_records[i].get('timestamp') - all_listen_records[i-1].get('timestamp')).total_seconds()
                    if interval < 86400:  # 只考虑一天内的间隔
                        time_intervals.append(interval)
            
            # 计算平均间隔和标准差
            if time_intervals:
                avg_interval = sum(time_intervals) / len(time_intervals)
                std_dev = (sum((x - avg_interval) ** 2 for x in time_intervals) / len(time_intervals)) ** 0.5
                user_data['listening_patterns']['avg_interval'] = avg_interval
                user_data['listening_patterns']['interval_std_dev'] = std_dev
                user_data['listening_patterns']['continuity_score'] = max(0, min(10, 10 - (std_dev / avg_interval) * 5)) if avg_interval > 0 else 0
            
            # 分析每日听歌时间的规律性
            daily_listen_hours = {}
            for record in all_listen_records:
                if isinstance(record.get('timestamp'), datetime):
                    hour = record.get('timestamp').hour
                    if hour in daily_listen_hours:
                        daily_listen_hours[hour] += 1
                    else:
                        daily_listen_hours[hour] = 1
            
            user_data['hour_preferences'] = daily_listen_hours
            
            # 计算规律性得分 - 听歌时间集中度
            total_listens = sum(daily_listen_hours.values())
            concentration = sum((count / total_listens) ** 2 for count in daily_listen_hours.values()) if total_listens > 0 else 0
            user_data['listening_patterns']['regularity_score'] = min(10, concentration * 10)
        
        # 优先使用新的统计数据格式
        # 从日统计获取详细数据
        with mongo_collection(Config.MONGODB_COLLECTIONS["daily_duration"]) as collection:
            daily_duration_records = list(collection.find({"user_id": user_id_int}))
            if not daily_duration_records:
                daily_duration_records = list(collection.find({"user_id": user_id}))
        
        # 从日期时段统计获取时段偏好
        with mongo_collection(Config.MONGODB_COLLECTIONS["daily_period_stats"]) as collection:
            daily_period_records = list(collection.find({"user_id": user_id_int}))
            if not daily_period_records:
                daily_period_records = list(collection.find({"user_id": user_id}))
        
        # 计算统计数据
        if daily_duration_records:
            # 计算总时长和活跃天数
            total_duration = sum(record.get("duration", 0) for record in daily_duration_records)
            user_data['listen_stats']['total_duration'] = total_duration
            user_data['listen_stats']['days_active'] = len(daily_duration_records)
            
            # 计算单日最高、最低、平均时长
            durations = [record.get("duration", 0) for record in daily_duration_records if record.get("duration", 0) > 0]
            if durations:
                user_data['listen_stats']['max_daily'] = max(durations)
                user_data['listen_stats']['min_daily'] = min(durations)
                user_data['listen_stats']['avg_daily'] = sum(durations) / len(durations)
        
        # 从时段统计计算时段偏好
        if daily_period_records:
            for record in daily_period_records:
                if "period_counts" in record:
                    for period, count in record["period_counts"].items():
                        if period in user_data['time_preferences']:
                            user_data['time_preferences'][period] += count
                        else:
                            user_data['time_preferences'][period] = count
                
                # 合并小时偏好
                if "exact_hour_counts" in record:
                    for hour, count in record["exact_hour_counts"].items():
                        hour_int = int(hour)
                        if hour_int in user_data['hour_preferences']:
                            user_data['hour_preferences'][hour_int] += count
                        else:
                            user_data['hour_preferences'][hour_int] = count
        
        # 如果新格式数据为空，尝试从旧格式获取
        if not daily_duration_records and not yearly_records:
            with mongo_collection(Config.MONGODB_COLLECTIONS["daily_preferences"]) as collection:
                # 使用整数类型用户ID查询
                daily_records = list(collection.find({"user_id": user_id_int}))
                
                if not daily_records:
                    # 尝试使用字符串类型的用户ID查询
                    daily_records = list(collection.find({"user_id": user_id}))
                
                # 计算活跃天数
                user_data['listen_stats']['days_active'] = len(daily_records)
                
                # 计算总时长
                total_duration = sum(record.get("total_duration", 0) for record in daily_records)
                user_data['listen_stats']['total_duration'] = total_duration
                
                # 找出单日最高和最低时长（只考虑有收听记录的日期）
                if daily_records:
                    durations = [record.get("total_duration", 0) for record in daily_records if record.get("total_duration", 0) > 0]
                    if durations:
                        user_data['listen_stats']['max_daily'] = max(durations)
                        user_data['listen_stats']['min_daily'] = min(durations)
                        user_data['listen_stats']['avg_daily'] = sum(durations) / len(durations)
                
                # 合并时间段偏好
                for record in daily_records:
                    if "period_preferences" in record:
                        for period, minutes in record["period_preferences"].items():
                            if period in user_data['time_preferences']:
                                user_data['time_preferences'][period] += minutes
                            else:
                                user_data['time_preferences'][period] = minutes
                
                # 获取最近活动记录
                if daily_records:
                    # 按日期排序
                    sorted_records = sorted(daily_records, key=lambda x: x.get('date', ''), reverse=True)
                    # 获取最近7天的记录
                    recent_records = sorted_records[:7]
                    for record in recent_records:
                        date = record.get('date')
                        if date:
                            user_data['recent_activity'][date] = {
                                'total_duration': record.get('total_duration', 0),
                                'period_preferences': record.get('period_preferences', {})
                            }
        else:
            # 使用新格式数据计算最近活动
            if daily_duration_records:
                # 按日期排序
                sorted_records = sorted(daily_duration_records, key=lambda x: x.get('date', ''), reverse=True)
                # 获取最近7天的记录
                recent_records = sorted_records[:7]
                for record in recent_records:
                    date = record.get('date')
                    if date:
                        user_data['recent_activity'][date] = {
                            'total_duration': record.get('duration', 0),
                            'listen_count': record.get('listen_count', 0)
                        }
        
        # 获取最近播放记录并分析艺术家偏好
        with mongo_collection(Config.MONGODB_COLLECTIONS["listen_records"]) as collection:
            recent_listens = list(collection.find(
                {"user_id": user_id_int}
            ).sort("timestamp", -1).limit(50))  # 增加获取数量以便更好地分析
            
            if not recent_listens:
                recent_listens = list(collection.find(
                    {"user_id": user_id}
                ).sort("timestamp", -1).limit(50))
            
            if recent_listens:
                user_data['recent_listens'] = []
                
                # 分析艺术家偏好
                artist_counts = {}
                
                for record in recent_listens:
                    # 优先分析记录中直接的艺术家信息（新格式）
                    if 'artists' in record and isinstance(record['artists'], list):
                        for artist_info in record['artists']:
                            if isinstance(artist_info, dict) and 'name' in artist_info:
                                artist_name = artist_info['name']
                                if artist_name in artist_counts:
                                    artist_counts[artist_name] += 1
                                else:
                                    artist_counts[artist_name] = 1
                    
                    # 如果没有直接的艺术家信息，从MySQL获取
                    song_id = record.get('song_id')
                    if song_id and not record.get('artists'):
                        song = Song.query.get(song_id)
                        if song:
                            # 统计艺术家
                            for artist in song.artists:
                                if artist.artist_name in artist_counts:
                                    artist_counts[artist.artist_name] += 1
                                else:
                                    artist_counts[artist.artist_name] = 1
                    
                    # 添加到最近播放列表
                    if len(user_data['recent_listens']) < 10:  # 只保留10条记录用于显示
                        listen_info = {
                            'song_id': record.get('song_id'),
                            'song_name': record.get('song_name'),
                            'timestamp': record.get('timestamp').isoformat() if isinstance(record.get('timestamp'), datetime) else record.get('timestamp'),
                            'period': record.get('period'),
                            'artists': record.get('artists', [])
                        }
                        user_data['recent_listens'].append(listen_info)
                
                # 保存艺术家偏好
                user_data['artist_preferences'] = artist_counts
        
        # 对时间段偏好进行排序
        sorted_periods = sorted(
            user_data['time_preferences'].items(), 
            key=lambda x: x[1], 
            reverse=True
        )
        user_data['time_preferences'] = dict(sorted_periods)
        
        # 对艺术家偏好进行排序
        if user_data['artist_preferences']:
            sorted_artists = sorted(
                user_data['artist_preferences'].items(),
                key=lambda x: x[1],
                reverse=True
            )
            user_data['artist_preferences'] = dict(sorted_artists)
        
        # 如果没有足够的数据，返回基础信息
        if not user_data['time_preferences'] and not user_data['artist_preferences']:
            return jsonify({
                "code": 0,
                "user_id": user_id_int,
                "message": "用户数据不足，无法生成画像",
                "basic_info": user_data['basic_info']
            }), 200
        
        # 调用DeepSeek API生成用户画像
        client = OpenAI(api_key=Config.DEEPSEEK_API_KEY, base_url="https://api.deepseek.com")
        
        # 构建时间段和风格偏好的描述
        time_prefs = ', '.join([f"{k}时段:{v}秒" for k, v in list(user_data['time_preferences'].items())[:3]])
        
        # 构建艺术家偏好描述
        artist_prefs = ', '.join([f"{k}:{v}次" for k, v in list(user_data['artist_preferences'].items())[:3]]) if user_data['artist_preferences'] else "无明显偏好"
        
        # 移除语言偏好描述
        language_prefs = "无明显偏好"
        
        # 构建听歌模式描述
        listening_pattern = ""
        if 'continuity_score' in user_data['listening_patterns'] and 'regularity_score' in user_data['listening_patterns']:
            listening_pattern = f"连续性得分:{user_data['listening_patterns']['continuity_score']:.1f}/10, 规律性得分:{user_data['listening_patterns']['regularity_score']:.1f}/10"
        
        # 修改后的提示词
        prompt = f"""
        基于以下用户听歌数据，生成简洁的用户画像描述，返回严格遵循如下JSON格式：
        {{
            "user_portrait": "概括性标签（20字内，要求生动有趣）",
            "description": "详细分析（150字内）",
            "recommendations": ["推荐1", "推荐2", "推荐3"]
        }}
        
        数据说明：
        1. 用户ID: {user_data['basic_info']['user_id']}
        2. 总听歌时长: {user_data['listen_stats']['total_duration']} 秒
        3. 活跃天数: {user_data['listen_stats']['days_active']} 天
        4. 主要时间段分布（秒）: {time_prefs}
        5. 艺术家偏好: {artist_prefs}
        6. 语言偏好: {language_prefs}
        7. 听歌模式: {listening_pattern}
        """
        
        if 'max_daily' in user_data['listen_stats'] and 'min_daily' in user_data['listen_stats']:
            prompt += f"\n9. 单日最高时长: {user_data['listen_stats']['max_daily']} 秒"
            prompt += f"\n10. 单日最低时长: {user_data['listen_stats']['min_daily']} 秒"
        
        if 'avg_daily' in user_data['listen_stats']:
            prompt += f"\n11. 日均时长: {user_data['listen_stats']['avg_daily']} 秒"
        
        # 添加小时分布数据
        if user_data['hour_preferences']:
            hour_data = sorted(user_data['hour_preferences'].items())
            hour_prefs = ', '.join([f"{k}点:{v}次" for k, v in hour_data])
            prompt += f"\n12. 小时分布: {hour_prefs}"
        
        prompt += """
        
        分析要求：
        - user_portrait需包含时间段+艺术家偏好，生动有趣
        - description需包含：
          * 听歌时段分布特征（使用具体时间段名称）
          * 艺术家偏好特征
          * 听歌活跃度和规律性分析
          * 典型使用场景推测
        - recommendations需包含：
          * 基于用户艺术家偏好的3条个性化建议
          * 可以是艺术家、场景或使用习惯建议
        """
        
        try:
            response = client.chat.completions.create(
                model="deepseek-chat",
                messages=[
                    {"role": "system", "content": "你是一个专业的音乐分析师，擅长从听歌数据中提炼用户特征"},
                    {"role": "user", "content": prompt},
                ],
                stream=False
            )
            
            ai_response = response.choices[0].message.content

            logger.info(f"用户画像AI原始响应 用户ID:{user_id}\n{ai_response}")
            
            try:
                # 新增：使用正则表达式提取JSON内容
                json_match = re.search(r'```(?:json)?\n({.*?})\n```', ai_response, re.DOTALL)
                
                if json_match:
                    cleaned_response = json_match.group(1).strip()
                else:
                    # 回退方案：尝试直接解析整个响应
                    cleaned_response = ai_response.strip()

                user_profile = json.loads(cleaned_response)
                
                # 返回修改后的结构
                return jsonify({
                    "code": 0,
                    "user_id": user_id_int,
                    "portrait": user_profile.get("user_portrait", ""),
                    "analysis": user_profile.get("description", ""),
                    "recommendations": user_profile.get("recommendations", []),
                    "stats": {
                        "total_duration": user_data['listen_stats']['total_duration'],
                        "days_active": user_data['listen_stats']['days_active'],
                        "time_preferences": user_data['time_preferences'],
                        "hour_preferences": user_data['hour_preferences'],
                        "artist_preferences": user_data['artist_preferences'],
                        "listening_patterns": user_data['listening_patterns']
                    },
                    "recent_activity": user_data['recent_activity'],
                    "recent_listens": user_data.get('recent_listens', [])
                }), 200
                
            except json.JSONDecodeError:
                logger.error(f"AI响应解析失败: {ai_response}")
                # 返回基础统计数据
                return jsonify({
                    "code": 0,
                    "user_id": user_id_int,
                    "message": "画像生成服务暂不可用",
                    "stats": {
                        "total_duration": user_data['listen_stats']['total_duration'],
                        "days_active": user_data['listen_stats']['days_active'],
                        "time_preferences": user_data['time_preferences'],
                        "hour_preferences": user_data['hour_preferences'],
                        "artist_preferences": user_data['artist_preferences'],
                        "listening_patterns": user_data['listening_patterns']
                    },
                    "recent_activity": user_data['recent_activity'],
                    "recent_listens": user_data.get('recent_listens', [])
                }), 200
                
        except Exception as e:
            logger.error(f"AI API错误: {str(e)}")
            # 返回基础统计数据
            return jsonify({
                "code": 0,
                "user_id": user_id_int,
                "message": "画像生成服务暂不可用",
                "stats": {
                    "total_duration": user_data['listen_stats']['total_duration'],
                    "days_active": user_data['listen_stats']['days_active'],
                    "time_preferences": user_data['time_preferences'],
                    "hour_preferences": user_data['hour_preferences'],
                    "artist_preferences": user_data['artist_preferences'],
                    "listening_patterns": user_data['listening_patterns']
                },
                "recent_activity": user_data['recent_activity'],
                "recent_listens": user_data.get('recent_listens', [])
            }), 200
            
    except Exception as e:
        logger.exception(f"获取用户画像异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500

@user_bp.route('/v1/search_song', methods=['GET'])
def search_song():
    """
    搜索歌曲接口
    请求示例：/api/v1/search_song?query_param=风铃&sort=auto&page=1&pagesize=20
    
    参数说明：
    - query_param: 搜索关键词，可以是歌曲名称、艺术家名称
    - sort: 排序方式，可选值：auto(默认)、popularity、duration_asc、duration_desc
    - page: 页码，默认为1
    - pagesize: 每页数量，默认为20
    """
    try:
        # 获取查询参数
        query_param = request.args.get('query_param', '')
        sort_method = request.args.get('sort', 'auto')
        
        # 获取分页参数
        try:
            page = int(request.args.get('page', 1))
            pagesize = int(request.args.get('pagesize', 20))
            
            # 验证分页参数
            if page < 1 or pagesize < 1:
                return jsonify(
                    code=40010,
                    message="页码和每页数量必须为正整数"
                ), 400
        except ValueError:
            return jsonify(
                code=40010,
                message="页码和每页数量必须为整数"
            ), 400
        
        # 验证排序方法
        valid_sort_methods = ['auto', 'popularity', 'duration_asc', 'duration_desc']
        if sort_method not in valid_sort_methods:
            return jsonify(
                code=40016,
                message=f"无效的排序方法，有效值为: {', '.join(valid_sort_methods)}"
            ), 400
        
        # 如果没有提供搜索关键词，返回错误
        if not query_param:
            return jsonify(
                code=40002,
                message="缺少搜索关键词"
            ), 400
        
        # 构建查询
        # 使用SQLAlchemy ORM进行模糊查询
        query = Song.query
        
        # 在歌曲名称和艺术家名称中搜索
        search_term = f"%{query_param}%"
        
        # 联合查询歌曲名和艺术家
        query = query.outerjoin(Song.artists).filter(
            or_(
                Song.song_name.like(search_term),
                Artist.artist_name.like(search_term)
            )
        ).distinct()
        
        # 应用排序
        if sort_method == 'duration_asc':
            query = query.order_by(Song.song_duration.asc())
        elif sort_method == 'duration_desc':
            query = query.order_by(Song.song_duration.desc())
        elif sort_method == 'popularity':
            # 这里假设我们有一个popularity字段或者通过其他方式计算流行度
            # 如果没有，可以使用MongoDB中的播放记录来计算
            # 这里暂时使用歌曲ID作为示例
            query = query.order_by(Song.song_id.desc())
        else:  # auto或其他
            # 默认排序逻辑，这里使用相关性排序（简化为名称匹配度）
            # 完全匹配的排在前面
            exact_matches = query.filter(Song.song_name == query_param).all()
            other_matches = query.filter(Song.song_name != query_param).all()
            
            # 手动合并结果
            songs = exact_matches + other_matches
            
            # 手动分页
            total_count = len(songs)
            songs = songs[(page-1)*pagesize:page*pagesize]
            
            # 构建响应
            result = {
                "code": 0,
                "message": "搜索成功",
                "pagination": {
                    "page": page,
                    "pagesize": pagesize,
                    "total": total_count,
                    "total_pages": (total_count + pagesize - 1) // pagesize
                },
                "songs": []
            }
            
            # 构建歌曲列表
            for song in songs:
                artists = [artist.artist_name for artist in song.artists]
                song_data = {
                    "song_id": song.song_id,
                    "song_name": song.song_name,
                    "duration": song.song_duration,
                    "artists": artists
                }
                result["songs"].append(song_data)
            
            return jsonify(result), 200
        
        # 如果不是auto排序，使用数据库排序和分页
        # 计算总数
        total_count = query.count()
        
        # 应用分页
        songs = query.paginate(page=page, per_page=pagesize, error_out=False).items
        
        # 构建响应
        result = {
            "code": 0,
            "message": "搜索成功",
            "pagination": {
                "page": page,
                "pagesize": pagesize,
                "total": total_count,
                "total_pages": (total_count + pagesize - 1) // pagesize
            },
            "songs": []
        }
        
        # 构建歌曲列表
        for song in songs:
            artists = [artist.artist_name for artist in song.artists]
            song_data = {
                "song_id": song.song_id,
                "song_name": song.song_name,
                "duration": song.song_duration,
                "artists": artists
            }
            result["songs"].append(song_data)
        return jsonify(result), 200
        
    except Exception as e:
        logger.exception(f"搜索歌曲异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500
        
@user_bp.route('/v1/user/RecomPlaylist', methods=['GET'])
def get_recommended_playlist():
    """
    获取推荐歌单接口
    请求示例：/api/v1/user/RecomPlaylist?user_id=123&size=20&type=common&scene=morning
    
    参数说明：
    - user_id: 用户ID
    - size: 返回歌曲数量，默认为20
    - type: 推荐类型，可选值：common(通用)、mood(情绪)
    - scene: 场景，可选值：morning(早晨)、work(工作)、relax(放松)、workout(运动)等
    """
    try:
        # 获取查询参数
        user_id = request.args.get('user_id')
        scene = request.args.get('scene', '')
        rec_type = request.args.get('type', 'common')
        
        # 获取歌曲数量参数
        try:
            size = int(request.args.get('size', 20))
            
            # 验证size参数
            if size < 1:
                return jsonify(
                    code=40010,
                    message="歌曲数量必须为正整数"
                ), 400
        except ValueError:
            return jsonify(
                code=40010,
                message="歌曲数量必须为整数"
            ), 400
        
        # 参数验证
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
        
        # 验证推荐类型
        valid_types = ['common', 'mood']
        if rec_type not in valid_types:
            return jsonify(
                code=40016,
                message=f"无效的推荐类型，有效值为: {', '.join(valid_types)}"
            ), 400
        
        # 验证场景类型
        valid_scenes = ['morning', 'work', 'relax', 'workout', 'travel', 'sleep', 'party', '']
        if scene and scene not in valid_scenes:
            return jsonify(
                code=40017,
                message=f"无效的场景类型，有效值为: {', '.join(valid_scenes)}"
            ), 400
        
        # 转换用户ID为整数类型
        user_id_int = int(user_id)
        
        # 检查用户是否存在
        user = User.query.get(user_id_int)
        if not user:
            return jsonify(
                code=404,
                message="用户不存在"
            ), 404
        
        # 根据不同的推荐类型和场景构建查询
        query = Song.query
        
        # 基于场景的推荐逻辑
        if scene:
            # 添加随机排序以增加推荐多样性
            query = query.order_by(db.func.rand())
        
        # 直接获取指定数量的歌曲
        songs = query.limit(size).all()
        total_count = len(songs)
        
        # 构建响应
        playlists = []
        
        # 根据不同的推荐类型和场景构建歌单名称
        playlist_name = "推荐歌单"
        if scene:
            scene_name_mapping = {
                'morning': '早晨',
                'work': '工作',
                'relax': '放松',
                'workout': '运动',
                'travel': '旅行',
                'sleep': '睡眠',
                'party': '派对'
            }
            playlist_name = f"{scene_name_mapping.get(scene, '日常')}音乐推荐"
        
        # 构建歌曲列表
        song_list = []
        for song in songs:
            artists = [artist.artist_name for artist in song.artists]
            song_data = {
                "song_id": song.song_id,
                "song_name": song.song_name,
                "duration": song.song_duration,
                "artists": artists
            }
            song_list.append(song_data)
        
        # 添加歌单
        playlists.append({
            "playlist_id": f"recom_{rec_type}_{scene if scene else 'general'}",
            "playlist_name": playlist_name,
            "cover_url": f"https://example.com/covers/{rec_type}_{scene if scene else 'general'}.jpg",
            "song_count": len(song_list),
            "songs": song_list
        })
        
        # 记录推荐日志到MongoDB
        try:
            with mongo_collection(Config.MONGODB_COLLECTIONS.get("recommendation_logs", "recommendation_logs")) as collection:
                collection.insert_one({
                    "user_id": user_id_int,
                    "timestamp": datetime.now(),
                    "recommendation_type": rec_type,
                    "scene": scene,
                    "songs_count": len(song_list),
                    "size": size
                })
        except Exception as e:
            # 日志记录失败不影响主流程
            logger.warning(f"推荐日志记录失败: {str(e)}")
        
        return jsonify({
            "code": 0,
            "message": "获取推荐歌单成功",
            "total": total_count,
            "playlists": playlists
        }), 200
        
    except Exception as e:
        logger.exception(f"获取推荐歌单异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500

@user_bp.route('/v1/get_devices', methods=['GET'])
def get_user_devices():
    """
    获取用户绑定的所有设备接口
    请求示例：/api/v1/get_devices?user_id=4
    
    参数说明：
    - user_id: 用户ID (必填)
    
    返回用户绑定的所有设备的ID、密钥及完整状态信息
    """
    try:
        user_id = request.args.get('user_id')
        
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
        
        user_id_int = int(user_id)
        devices = Device.query.filter_by(user_id=user_id_int).all()
        
        device_list = []
        for device in devices:
            with mongo_collection(Config.MONGODB_COLLECTIONS["device_status"]) as collection:
                status = collection.find_one(
                    {"device_id": device.device_id},
                    sort=[("timestamp", -1)]
                )
                
            device_info = {
                "device_id": device.device_id,
                "device_key": device.device_key,
                "create_at": device.create_at.isoformat() if device.create_at else None,
                "firmware_version": "1.2.0",
                "is_activated": device.is_activated,
                "activation_time": device.activation_time.isoformat() if device.activation_time else None,
                "last_online": status.get("timestamp").isoformat() if status and "timestamp" in status else None,
                "status": {}
            }
            
            # 添加详细状态信息
            if status:
                device_info["status"] = {
                    "connection_status": status.get("connection_status", "UNKNOWN"),
                    "activation_status": status.get("activation_status", "UNKNOWN"),
                    "power": {
                        "state": status.get("power", {}).get("state", "UNKNOWN"),
                        "battery_level": status.get("power", {}).get("battery_level", 0),
                        "charging_state": status.get("power", {}).get("charging_state", "UNKNOWN")
                    },
                    "network": {
                        "wifi_state": status.get("network", {}).get("wifi_state", "UNKNOWN"),
                        "net_delay": status.get("network", {}).get("net_delay", 0)
                    },
                    "audio": {
                        "effect": status.get("audio", {}).get("effect", "Common"),
                        "mode": status.get("audio", {}).get("mode", "Sequential")
                    }
                }
            else:
                # 没有状态记录时的默认值
                device_info["status"] = {
                    "connection_status": "OFFLINE",
                    "activation_status": "ACTIVATED" if device.is_activated else "INACTIVATED",
                    "power": {
                        "state": "UNKNOWN",
                        "battery_level": 0,
                        "charging_state": "UNKNOWN"
                    },
                    "network": {
                        "wifi_state": "DISCONNECTED",
                        "net_delay": 0
                    },
                    "audio": {
                        "effect": "Common",
                        "mode": "Sequential"
                    }
                }
                
            device_list.append(device_info)
        
        response = {
            "code": 0,
            "message": "获取用户设备成功",
            "user_id": user_id_int,
            "devices": device_list
        }
        
        return jsonify(response), 200
        
    except Exception as e:
        logger.exception(f"获取用户设备异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试",
            error=str(e)
        ), 500

@user_bp.route('/v1/wechat_login', methods=['POST'])
def wechat_login():
    """
    微信快捷登录/注册接口
    请求示例：
    {
        "js_code": "123456"
    }
    """
    try:
        # 1. 获取并校验请求数据
        if not request.is_json:
            return jsonify({
                "code": Config.ERROR_CODES['INVALID_JSON'][0],
                "message": Config.ERROR_CODES['INVALID_JSON'][1]
            }), 400

        data = request.get_json()
        js_code = data.get('js_code')
        
        # 验证必填字段
        if not js_code:
            return jsonify({
                "code": Config.ERROR_CODES['MISSING_FIELD'][0],
                "message": f"{Config.ERROR_CODES['MISSING_FIELD'][1]}: js_code"
            }), 400
        
        # 2. 从配置中获取微信小程序的appid和secret
        appid = Config.WECHAT_APPID
        secret = Config.WECHAT_SECRET
        grant_type = "authorization_code"
        
        # 3. 调用微信 auth.code2Session 接口
        wx_api_url = "https://api.weixin.qq.com/sns/jscode2session"
        params = {
            "appid": appid,
            "secret": secret,
            "js_code": js_code,
            "grant_type": grant_type
        }
        
        try:
            response = requests.get(wx_api_url, params=params)
            wx_data = response.json()
            
            # 检查微信接口返回是否成功
            if 'errcode' in wx_data and wx_data['errcode'] != 0:
                logger.error(f"微信接口调用失败: {wx_data}")
                return jsonify({
                    "code": 40020,
                    "message": f"微信授权失败: {wx_data.get('errmsg', '未知错误')}"
                }), 400
                
            # 获取openid和unionid
            openid = wx_data.get('openid')
            unionid = wx_data.get('unionid', '')  # unionid可能不存在
            
            if not openid:
                logger.error("微信接口未返回openid")
                return jsonify({
                    "code": 40021,
                    "message": "微信授权失败: 未获取到用户标识"
                }), 400
                
        except Exception as e:
            logger.error(f"调用微信接口异常: {str(e)}")
            return jsonify({
                "code": 50010,
                "message": "微信服务调用失败"
            }), 500
        
        # 4. 查询是否存在以openid为用户名的用户
        user = User.query.filter_by(user_name=openid).first()
        
        if user:
            # 用户存在，执行登录逻辑
            logger.info(f"微信用户已存在，执行登录: {openid}")
            
            # 获取用户绑定的设备
            devices = Device.query.filter_by(user_id=user.user_id).all()
            device_list = [{
                "device_id": device.device_id,
                "secret": device.device_key
            } for device in devices]
            
            # 记录登录日志到MongoDB
            with mongo_collection(Config.MONGODB_COLLECTIONS["user_logs"]) as collection:
                collection.insert_one({
                    "user_id": user.user_id,
                    "username": openid,
                    "operation": "wechat_login",
                    "timestamp": datetime.now(),
                    "ip": get_client_ip()
                })
            
            return jsonify({
                "code": 0,
                "user_id": user.user_id,
                "username": user.user_name,
                "devices": device_list
            }), 200
            
        else:
            # 用户不存在，执行注册逻辑
            logger.info(f"微信用户不存在，执行注册: {openid}")
            
            # 使用openid作为用户名，unionid作为密码（如果没有unionid，使用openid作为密码）
            username = openid
            password = unionid if unionid else openid
            
            # 哈希密码
            password_bytes = password.encode('utf-8')
            salt = bcrypt.gensalt()
            hashed_password = bcrypt.hashpw(password_bytes, salt).decode('utf-8')
            
            try:
                # 创建新用户
                new_user = User(
                    user_name=username,
                    user_key=hashed_password,
                    register_at=datetime.now()
                )
                
                db.session.add(new_user)
                db.session.commit()
                
                # 记录注册日志到MongoDB
                with mongo_collection(Config.MONGODB_COLLECTIONS["user_logs"]) as collection:
                    collection.insert_one({
                        "user_id": new_user.user_id,
                        "username": username,
                        "operation": "wechat_register",
                        "timestamp": datetime.now(),
                        "ip": get_client_ip()
                    })
                
                # 新用户没有绑定设备，返回空列表
                return jsonify({
                    "code": 0,
                    "user_id": new_user.user_id,
                    "username": new_user.user_name,
                    "devices": []
                }), 200
                
            except Exception as e:
                db.session.rollback()
                logger.error(f"微信用户创建失败: {str(e)}")
                raise
                
    except pymysql.IntegrityError:
        logger.warning(f"用户名重复: {openid}")
        return jsonify(
            code=Config.ERROR_CODES['DUPLICATE_USER'][0],
            message=Config.ERROR_CODES['DUPLICATE_USER'][1]
        ), 400
    except Exception as e:
        logger.exception(f"微信登录/注册异常: {str(e)}")
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试"
        ), 500

@user_bp.route('/v1/update_nickname', methods=['POST'])
def update_nickname():
    """
    更新用户昵称接口
    请求示例：
    {
        "user_id": 4,
        "nickname": "fourzkw"
    }
    """
    try:
        # 获取请求数据
        data = request.get_json()
        
        # 参数验证
        if not data:
            return jsonify(
                code=40001,
                message="无效的请求数据格式"
            ), 400
            
        user_id = data.get('user_id')
        nickname = data.get('nickname')
        
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not nickname:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: nickname"
            ), 400
            
        if not validate_user_id(str(user_id)):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
            
        # 转换用户ID为整数类型
        user_id_int = int(user_id)
        
        # 准备存储数据
        nickname_data = {
            "user_id": user_id_int,
            "nickname": nickname,
            "updated_at": datetime.now()
        }
        
        # 存储到MongoDB
        with mongo_collection(Config.MONGODB_COLLECTIONS.get("user_profile", "user_profile")) as collection:
            # 使用upsert模式，如果记录存在则更新，不存在则插入
            result = collection.update_one(
                {"user_id": user_id_int},
                {"$set": nickname_data},
                upsert=True
            )
            
            if result.acknowledged:
                # 记录用户资料更新日志
                with mongo_collection(Config.MONGODB_COLLECTIONS["user_logs"]) as collection:
                    collection.insert_one({
                        "user_id": user_id_int,
                        "operation": "update_profile",
                        "timestamp": datetime.now(),
                        "ip": get_client_ip(),
                        "details": {
                            "nickname": nickname
                        }
                    })
                
                return jsonify({
                    "code": 0,
                    "message": "用户昵称更新成功",
                    "user_id": user_id_int,
                    "nickname": nickname
                }), 200
            else:
                return jsonify({
                    "code": 50003,
                    "message": "数据库操作失败"
                }), 500
                
    except Exception as e:
        print(f"[SYSTEM ERROR] 更新用户昵称异常: {str(e)}")
        import traceback
        traceback.print_exc()  # 打印完整堆栈跟踪
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试",
            error=str(e)
        ), 500

@user_bp.route('/v1/get_nickname', methods=['GET'])
def get_nickname():
    """
    获取用户昵称接口
    请求示例：/api/v1/get_nickname?user_id=4
    """
    try:
        # 获取用户ID参数
        user_id = request.args.get('user_id')
        
        # 参数验证
        if not user_id:
            return jsonify(
                code=Config.ERROR_CODES['MISSING_FIELD'][0],
                message="缺少必要参数: user_id"
            ), 400
            
        if not validate_user_id(user_id):
            return jsonify(
                code=40007,
                message="无效的用户ID格式"
            ), 400
            
        # 转换用户ID为整数类型
        user_id_int = int(user_id)
        
        # 从MongoDB获取用户昵称
        with mongo_collection(Config.MONGODB_COLLECTIONS.get("user_profile", "user_profile")) as collection:
            user_profile = collection.find_one({"user_id": user_id_int})
            
            if user_profile and "nickname" in user_profile:
                return jsonify({
                    "code": 0,
                    "message": "获取用户昵称成功",
                    "user_id": user_id_int,
                    "nickname": user_profile["nickname"]
                }), 200
            else:
                return jsonify({
                    "code": 40404,
                    "message": "未找到用户昵称信息",
                    "user_id": user_id_int
                }), 404
                
    except Exception as e:
        print(f"[SYSTEM ERROR] 获取用户昵称异常: {str(e)}")
        import traceback
        traceback.print_exc()  # 打印完整堆栈跟踪
        return jsonify(
            code=50000,
            message="系统繁忙，请稍后重试",
            error=str(e)
        ), 500